import type { ResponsePromise } from "ky"

import { sendToContentScript, type PlasmoMessaging } from "@plasmohq/messaging"

import type { ChatMessageType } from "~type/chatType"

import { isJSON } from "./jsonUtil"

export async function chatSSEAPIPort<T, P>({
  requestAPI,
  req,
  res
}: {
  requestAPI: (data: T) => ResponsePromise
  req: P | any
  res: PlasmoMessaging.Response<ChatMessageType>
}) {
  const chatRes = await requestAPI(req.body)

  const headerStr = chatRes.headers.get("Content-Type")
  if (headerStr.includes("application/json")) {
    const json = await chatRes.json<ChatMessageType>()
    // console.log(json)
    sendToContentScript({
      name: "chat-message",
      body: json
    })
  } else if (headerStr.includes("text/event-stream")) {
    const reader = chatRes.body.getReader()
    eventStream(reader, res)
  }
}

function eventStream(
  reader: ReadableStreamDefaultReader<Uint8Array>,
  res: PlasmoMessaging.Response<ChatMessageType>
) {
  let chunk: string = ""
  push(reader, (val: string) => {
    if (val.length > 0) {
      console.log("val", val)
      val
        .trim()
        .split("\n")
        .forEach((line) => {
          if (line.trim() && line.length > 0 && !line.includes("[DONE]")) {
            console.log(line)
            if (isJSON(line)) {
              const json = JSON.parse(line)

              sendToContentScript({
                name: "chat-message",
                body: json
              })
            } else {
              if (chunk && chunk.trim()) {
                chunk = chunk.replaceAll("\n", "").trim() + line.trim()
                console.log("chunk", chunk)
                const json = JSON.parse(chunk)
                sendToContentScript({
                  name: "chat-message",
                  body: json
                })
                chunk = ""
                // console.error(err)
              } else {
                chunk = line.trim()
              }
            }
          }

          // res.send(json)
        })
    }
  })
}

const push = async (reader, onMsg?: (msg: string) => void) => {
  const { value, done } = await reader.read()
  if (done) {
    return
  } else {
    onMsg && onMsg(Buffer.from(value).toString().replaceAll("data:", ""))

    push(reader, onMsg)
  }
}
